use std::ops::Range;

use super::*;

#[derive(Default, Debug, Clone)]
pub struct TopDict {
	pub charset_offset: Option<usize>,
	pub encoding_offset: Option<usize>,
	pub char_strings_offset: usize,
	pub private_dict_range: Option<Range<usize>>,
	pub matrix: Matrix,
	pub has_ros: bool,
	pub fd_array_offset: Option<usize>,
	pub fd_select_offset: Option<usize>,
}
impl TopDict {
	pub fn parse(data: &[u8]) -> Option<Self> {
		let mut top_dict = TopDict::default();

		let mut operands_buffer = [0.0; MAX_OPERANDS_LEN];
		let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
		while let Some(operator) = dict_parser.parse_next() {
			match operator.get() {
				operator::CHARSET_OFFSET => {
					top_dict.charset_offset = dict_parser.parse_offset();
				}
				operator::ENCODING_OFFSET => {
					top_dict.encoding_offset = dict_parser.parse_offset();
				}
				operator::CHAR_STRINGS_OFFSET => {
					top_dict.char_strings_offset = dict_parser.parse_offset()?;
				}
				operator::PRIVATE_DICT_SIZE_AND_OFFSET => {
					top_dict.private_dict_range = dict_parser.parse_range();
				}
				operator::FONT_MATRIX => {
					dict_parser.parse_operands()?;
					let operands = dict_parser.operands();
					if operands.len() == 6 {
						top_dict.matrix = Matrix {
							sx: operands[0] as f32,
							ky: operands[1] as f32,
							kx: operands[2] as f32,
							sy: operands[3] as f32,
							tx: operands[4] as f32,
							ty: operands[5] as f32,
						};
					}
				}
				operator::ROS => {
					top_dict.has_ros = true;
				}
				operator::FD_ARRAY => {
					top_dict.fd_array_offset = dict_parser.parse_offset();
				}
				operator::FD_SELECT => {
					top_dict.fd_select_offset = dict_parser.parse_offset();
				}
				_ => {}
			}
		}

		Some(top_dict)
	}
}

pub fn parse_font_dict(data: &[u8]) -> Option<Range<usize>> {
	let mut operands_buffer = [0.0; MAX_OPERANDS_LEN];
	let mut dict_parser = DictionaryParser::new(data, &mut operands_buffer);
	while let Some(operator) = dict_parser.parse_next() {
		if operator.get() == operator::PRIVATE_DICT_SIZE_AND_OFFSET {
			return dict_parser.parse_range();
		}
	}

	None
}

/// Enumerates some operators defined in the Adobe Technical Note #5176,
/// Table 9 Top DICT Operator Entries
mod operator {
	pub const CHARSET_OFFSET: u16 = 15;
	pub const ENCODING_OFFSET: u16 = 16;
	pub const CHAR_STRINGS_OFFSET: u16 = 17;
	pub const PRIVATE_DICT_SIZE_AND_OFFSET: u16 = 18;
	pub const FONT_MATRIX: u16 = 1207;
	pub const ROS: u16 = 1230;
	pub const FD_ARRAY: u16 = 1236;
	pub const FD_SELECT: u16 = 1237;
}

/// An affine transformation matrix.
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
pub struct Matrix {
	pub sx: f32,
	pub ky: f32,
	pub kx: f32,
	pub sy: f32,
	pub tx: f32,
	pub ty: f32,
}
impl Default for Matrix {
	fn default() -> Self {
		Self {
			sx: 0.001,
			ky: 0.0,
			kx: 0.0,
			sy: 0.001,
			tx: 0.0,
			ty: 0.0,
		}
	}
}
